﻿using System;
using System.Collections.Generic;
using System.Text;
using Sofire.Dynamic.Factories;
using Sofire.Dynamic;
using System.Data;
using System.Reflection;

namespace Sofire.Data
{
    /// <summary>
    /// 数据行与实体的映射。
    /// </summary>
    public class RowMapper : IRowMapper
    {
        /// <summary>
        ///表示 <see cref="Sofire.Data.IRowMapper"/>的类型。
        /// </summary>
        public readonly static Type IType = typeof(IRowMapper);

        private Dictionary<string, HandlerInfo<DynamicGetMemberHandler>> inner;
        private RowMapper(int capacity)
        {
            inner = new Dictionary<string, HandlerInfo<DynamicGetMemberHandler>>(capacity, StringComparer.CurrentCultureIgnoreCase);
        }

        private Type _InstanceType;
        /// <summary>
        /// 设置或获取实例的类型。
        /// </summary>
        public Type InstanceType
        {
            get
            {
                return this._InstanceType;
            }
        }

        private static readonly Dictionary<Type, IRowMapper> Cacher
            = new Dictionary<Type, IRowMapper>();

        /// <summary>
        /// 将指定的实体填充到数据行。
        /// </summary>
        /// <param name="form">实例。</param>
        /// <param name="to">数据行。</param>
        public virtual void FillRow(object form, DataRow to)
        {
            if(form == null) return;
            HandlerInfo<DynamicGetMemberHandler> handlerInfo;
            string name;
            object rowValue, entityValue;

            foreach(DataColumn column in to.Table.Columns)
            {
                name = column.ColumnName;
                rowValue = to[column];

                if(!inner.TryGetValue(name, out handlerInfo))
                {
                    if(QueryEngineBase.IgnoreUnfoundEntityProperty) continue;
                    throw new KeyNotFoundException("填充数据时候发生错误，无法在 " + form.GetType().FullName + " 找到字段 " + name + " 对应的属性成员。");
                }
                entityValue = handlerInfo.Handler(form) ?? DBNull.Value;
                if(object.Equals(entityValue, rowValue)) continue;
                to[column] = this.CheckValue(to, column, entityValue);
            }
        }

        /// <summary>
        /// 检查指定数据行的列值。
        /// </summary>
        /// <param name="row">数据行。</param>
        /// <param name="column">列。</param>
        /// <param name="value">列的值。</param>
        /// <returns>返回新的列值。</returns>
        protected virtual object CheckValue(DataRow row, DataColumn column, object value)
        {
            return value;
        }

        /// <summary>
        /// 指定实例的数据类型，创建或从缓存读取一个读取器映射。
        /// </summary>
        /// <param name="type">实例的数据类型。</param>
        /// <returns>返回一个读取器的映射。</returns>
        public static IRowMapper Create(Type type)
        {
            var attr = type.GetAttribute<EntityRowAttribute>();
            if(attr != null && attr.Row != null) return attr.Row;

            IRowMapper collection;
            lock(type)
            {
                if(Cacher.TryGetValue(type, out collection)) return collection;
                if(RowMapper.IType.IsAssignableFrom(type))
                {
                    collection = Activator.CreateInstance(type) as IRowMapper;
                }
                else
                {
                    var ps = type.GetProperties();
                    var collection2 = new RowMapper(ps.Length);
                    collection2._InstanceType = type;
                    foreach(var p in ps)
                    {
                        if(p.CanRead)
                            collection2.inner.Add(p.Name
                                , new HandlerInfo<DynamicGetMemberHandler>(p
                                    , DynamicGetPropertyFactory.Instance.Create(p, type)));
                    }
                    collection = collection2;
                }
                Cacher.Add(type, collection);
                return collection;
            }
        }
    }
}
